/*
  Dobry's benchmarks
*/

/* CHANGELOG by M.Banbara 
   - [X,..Y]       -->  comment out
   - not(X)        -->  \+(X)
   - is(N2,N1,+,1) -->  N2 is N1+1
   - write/1, nl/0 --> comment out
*/

/****************************************************************************
Here it is, I hope (I think I have left the code untouched, but I am not 100%
sure). It comes from Tep Dobry when he was at UCB.

By the way, these benchmarks are somehow outdated. Do you know about the
benchmark
suite used for assessing the BAM and the Aquarius Prolog Compiler? It is
available by anonymous FTP from UCB. The suite of F. Pereira (published
on the net in 86 or 87) is also quite interesting (it tries to test
specific operations,
unification, indexing, backtracking...).

-- Jacques NOYE

From: (Tep Dobry) Tep%ucbdali@Berkeley 
Subject: The Berkeley PLM Benchmarks
Date:    Wednesday, May 22 1985

     At the Warren Abstract Machine Workshop a few weeks ago
I  was  asked to publish the set of benchmarks programs I've
been  using  on  my  simulator  for  the   Berkeley   Prolog
Machine(PLM).  I've  finally got them all collected together
in Prolog form (CProlog) and have sent them to  the  Digest.
They're  really  too  big  to just publish in the Digest, so
they are being set up in a directory in the PROLOG directory
at  SU-SCORE.  There are 11 files with a total of 400 lines.
Since our machine is based on compiled Prolog, the top level
queries  are  also  compiled  in, generally as the predicate
main/0.

     The benchmarks were primarily chosen to exercise all of
the  features of the PLM, not for any complexity of program-
ming. About half of them come from Warren's thesis, and  the
others  we've  added here.  Our original performance figures
were based on simulations of hand compiled versions of these
benchmarks.   We are currently looking for larger, more com-
plex benchmarks to run on the hardware when it is available.
So  I'd  be  interested  seeing large benchmarks sent to the
Digest.

-- Tep Dobry (TEP@Berkeley)
****************************************************************************/

%	concat (con1, con6)
%	These two tests are simple examples of the concat predicate
%	con1 is determinate, con6 is non-determinate getting all 6 answers

con1 :- concat([a,b,c],[d,e],X).  % con1
	%write(X),nl.
con6 :- concat(X,Y,[a,b,c,d,e]),  % con6
	%write(X),nl,
	%write(Y),nl,nl,
	fail.

concat([],L,L).
concat([X|L1],L2,[X|L3]) :- concat(L1,L2,L3).


%	differen (times10,divide10,log10,ops8)
%	These 4 examples are from Warren's thesis

diff :-
	times10(I1),
	d(I1,x,D1),
	%write(D1), nl,
	divide10(I2),
	d(I2,x,D2),
	%write(D2), nl,
	log10(I3),
	d(I3,x,D3),
	%write(D3), nl,
	ops8(I4),
	d(I4,x,D4).
	%write(D4), nl.

d(U+V,X,DU+DV) :- !, d(U,X,DU), d(V,X,DV).
d(U-V,X,DU-DV) :- !, d(U,X,DU), d(V,X,DV).
d(U*V,X,DU*V+U*DV) :- !, d(U,X,DU), d(V,X,DV).
d(U/V,X,(DU*V-U*DV)/(^(V,2))) :- !, d(U,X,DU), d(V,X,DV).
d(^(U,N),X,DU*N*(^(U,N1))) :- !, integer(N), N1 is N - 1, d(U,X,DU).
d(-U,X,-DU) :- !, d(U,X,DU).
d(exp(U),X,exp(U)*DU) :- !, d(U,X,DU).
d(log(U),X,DU/U) :- !, d(U,X,DU).
d(X,X,1).	% There is a cut in Warren's program! -- Jacques
d(C,X,0).

times10( ((((((((x*x)*x)*x)*x)*x)*x)*x)*x)*x ).
divide10( ((((((((x/x)/x)/x)/x)/x)/x)/x)/x)/x ).
log10( log(log(log(log(log(log(log(log(log(log(x)))))))))) ).
ops8( (x+1)*((^(x,2)+2)*(^(x,3)+3)) ).



%	towers of hanoi ( hanoi ) for 8 disks

hanoi :- hanoi(8).

hanoi(N) :- move(N,left,center,right).

move(0,_,_,_) :- !.
%move(N,A,B,C) :- M is N-1, move(M,A,C,B), inform(A,B), move(M,C,B,A).
move(N,A,B,C) :- M is N-1, move(M,A,C,B), move(M,C,B,A).

inform(A,B) :- write([move,disk,from,A,to,B]), nl, fail.
inform(_,_).

/*
% Main program to do branch and bound NAND gate designs.
% Optimized for 2-input NAND gates and 3 input variables.
% A. Despain, Feb 84.
% In this case, design a 2-1 MUX (ckt2)

main :- set_bound(32000), update_circuit([],0), r(0, [0,0,1,1,0,1,0,1]).

run(Depth, Table, Circuit, Cost, Depth) :- search(Depth, Table),
					   circuit(Circuit),
                                           Circuit\==[],
                                           cost_bound(Cost),!.
run(Depth, Table, Circuit, Cost, Delay) :- D is Depth + 1,
    run(D, Table, Circuit, Cost, Delay),!.

search(Depth, Table) :- t(Depth, Circuit, Table, 0, Cost_out),
			update_circuit(Circuit,Cost_out),
			update_bound(Cost_out).

% Input signals are free and terminate the search.
t(_, 0 , [0,1,0,1,0,1,0,1],C,C).
t(_, 1 , [0,0,1,1,0,0,1,1],C,C).
t(_, 2 , [0,0,0,0,1,1,1,1],C,C).
t(_,i0 , [1,0,1,0,1,0,1,0],C,C).
t(_,i1 , [1,1,0,0,1,1,0,0],C,C).
t(_,i2 , [1,1,1,1,0,0,0,0],C,C).

% Inverters are free in this model.
t(Depth, [i,Z], Table, Cin, Cout) :- Depth > 0,
				 D is Depth -1,
				 sint(Table, Itable),
				 t(D, Z, Itable, Cin, Cout).

% Main NAND gate clause.
t(Depth, [n,Y,Z], Table, Cin, Cout) :- Depth > 0,
				 D is Depth -1,
				 update_cost(Cin,1,C2),
				 ngate(Table, A, B),
				 t(D,Y,A,C2,C3),
				 t(D,Z,B,C3,Cout).

% Inverter signal transformation.
%sint([H1,..T1],[H2,..T2]) :- inv(H1, H2), sint(T1, T2).
sint([],[]).
sint([X,..T1],[_,..T2]) :- var(X), sint(T1, T2),!.
sint([0,..T1],[1,..T2]) :- sint(T1, T2).
sint([1,..T1],[0,..T2]) :- sint(T1, T2).

% Optimized gate signal transformation.
ngate([], [], []).
tgate([], [], []).
ngate([X,..T0], [_,..T1], [_,..T2]) :- var(X), !, ngate(T0, T1, T2).
ngate([X,..T0], [1,..T1], [1,..T2]) :- X==0, ngate(T0, T1, T2).
ngate([X,..T0], [_,..T1], [0,..T2]) :- X==1, tgate(T0, T1, T2).
tgate([X,..T0], [_,..T1], [_,..T2]) :- var(X), !, tgate(T0, T1, T2).
tgate([X,..T0], [1,..T1], [1,..T2]) :- X==0, tgate(T0, T1, T2).
tgate([X,..T0], [_,..T1], [0,..T2]) :- X==1, tgate(T0, T1, T2).
tgate([X,..T0], [0,..T1], [_,..T2]) :- X==1, tgate(T0, T1, T2).


r(Depth,Table) :- run(0, Table, L, C, D),
                  Depth =< D,
	          nl, write([minimum,cost,circuit,of,the,shortest,delay]),
	          nl, write([  circuit,=,L]),
	          nl, write([  cost,is,C,gates]),
	          nl, write([  delay,is,D,gate,times]),nl,!.
r(Depth,Table) :- run(Depth, Table, L, C, D),
	          nl, write([lowest,cost,circuit,for,a,given,delay]),
	          nl, write([  circuit,=,L]),
	          nl, write([  cost,is,C,gates]),
	          nl, write([  delay,is,D,gate,times]),nl.

%Utility procedures

min(X,Y,X) :- X < Y , ! .
min(X,Y,Y).

update_cost(Cost_in, Cost, Cost_out) :- Cost_out is Cost_in + Cost,
					cost_bound(B),
					Cost_out < B, ! .

cost_bound(32000).

set_bound(X) :- retract((cost_bound(_))),
		assert((cost_bound(X))), ! .

update_bound(X) :- retract((cost_bound(Y))),
		   min(X,Y,Z),
		   assert((cost_bound(Z))), ! .

update_circuit(Circuit,Cost) :- cost_bound(X),
				Cost < X ,
				retract((circuit(_))),
				assert((circuit(Circuit))),!.
update_circuit(Circuit,Cost).

circuit([]).
*/

%  Hofstader's mu math (mutest) proving muiiu
%	from Godel Escher Bach

mu :- theorem(5,[m,u,i,i,u]).

rules(S, R) :- rule3(S,R).
rules(S, R) :- rule4(S,R).
rules(S, R) :- rule1(S,R).
rules(S, R) :- rule2(S,R).

rule1(S,R) :-
	append(X, [i], S),
	append(X, [i,u], R).

rule2([m | T], [m | R]) :- append(T, T, R).

rule3([], -) :- fail.
rule3(R, T) :-
	append([i,i,i], S, R),
	append([u], S, T).
rule3([H | T], [H | R]) :- rule3(T, R).

rule4([], -) :- fail.
rule4(R, T) :- append([u, u], T, R).
rule4([H | T], [H | R]) :- rule4(T, R).

theorem(Depth, [m, i]).
theorem(Depth, []) :- fail.

theorem(Depth, R) :-
	Depth > 0,
	D is Depth - 1,
	theorem(D, S),
	rules(S, R).

append([], X, X).
append([A | B], X, [A | B1]) :-
	!,
	append(B, X, B1).


%	naive reverse (nrev1)
%	from Warren's thesis

nrev1 :-
	list30(L),
	nreverse(L,X).
	%write(X), nl.

nreverse([X|L0],L) :- nreverse(L0,L1), concatenate(L1,[X],L).
nreverse([],[]).

concatenate([X|L1],L2,[X|L3]) :- concatenate(L1,L2,L3).
concatenate([],L,L).

list30([1,2,3,4,5,6,7,8,9,10,11,12,
	13,14,15,16,17,18,19,20,21,
	22,23,24,25,26,27,28,29,30]).


%	the queens on a chessboard problem (queens) for 4x4 board

queens :-  run(4,X), fail.

size(4).
int(1).
int(2).
int(3).
int(4).

%run(Size, Soln) :- get_solutions(Size, Soln), inform(Soln).
run(Size, Soln) :- get_solutions(Size, Soln).

get_solutions(Board_size, Soln) :- solve(Board_size, [], Soln).

%	newsquare generates legal positions for next queen

newsquare([], square(1, X)) :- int(X).
newsquare([square(I, J) | Rest], square(X, Y)) :-
	X is I + 1,
	int(Y),
	\+(threatened(I, J, X, Y)),
	safe(X, Y, Rest).


%	safe checks whether square(X, Y) is threatened by any
%	existing queens

safe(X, Y, []).
safe(X, Y, [square(I, J) | L]) :-
	\+(threatened(I, J, X, Y)),
	safe(X, Y, L).


%	threatened checks whether squares (I, J) and (X, Y)
%	threaten each other

threatened(I, J, X, Y) :-
	(I = X),
	!.
threatened(I, J, X, Y) :-
	(J = Y),
	!.
threatened(I, J, X, Y) :-
	(U is I - J),
	(V is X - Y),
	(U = V),
	!.
threatened(I, J, X, Y) :-
	(U is I + J),
	(V is X + Y),
	(U = V),
	!.


%	solve accumulates the positions of occupied squares

solve(Bs, [square(Bs, Y) | L], [square(Bs, Y) | L]) :- size(Bs).
solve(Board_size, Initial, Final) :-
	newsquare(Initial, Next),
	solve(Board_size, [Next | Initial], Final).

inform([]) :- nl,nl.
inform([M | L]) :- write(M), nl, inform(L).

%	query
%	from Warren's thesis

query :-
	query(X),
	%write(X), nl,
	fail.

query([C1,D1,C2,D2]) :- 
	density(C1,D1), 
	density(C2,D2),
	D1 > D2,
	T1 is 20*D1,
	T2 is 21*D2,
	T1 < T2.

density(C,D) :- pop(C,P), area(C,A), D is (P*100)//A.

pop(china,	8250).	area(china,	3380).
pop(india,	5863).	area(india,	1139).
pop(ussr,	2521).	area(ussr,	8708).
pop(usa,	2119).	area(usa,	3609).
pop(indonesia,	1276).	area(indonesia,	570).
pop(japan,	1097).	area(japan,	148).
pop(brazil,	1042).	area(brazil,	3288).
pop(bangladesh,	750).	area(bangladesh,55).
pop(pakistan,	682).	area(pakistan,	311).
pop(w_germany,	620).	area(w_germany,	96).
pop(nigeria,	613).	area(nigeria,	373).
pop(mexico,	581).	area(mexico,	764).
pop(uk,		559).	area(uk,	86).
pop(italy,	554).	area(italy,	116).
pop(france,	525).	area(france,	213).
pop(phillipines,415).	area(phillipines,90).
pop(thailand,	410).	area(thailand,	200).
pop(turkey,	383).	area(turkey,	296).
pop(egypt,	364).	area(egypt,	386).
pop(spain,	352).	area(spain,	190).
pop(poland,	337).	area(poland,	121).
pop(s_korea,	335).	area(s_korea,	37).
pop(iran,	320).	area(iran,	628).
pop(ethiopia,	272).	area(ethiopia,	350).
pop(argentina,	251).	area(argentina,	1080).


%	quicksort (qs4) on 50 items
%	from Warren's thesis

qs4 :-
	list50(L),
	qsort(L,X,[]).
	%write(X), nl.

qsort([X|L],R,R0) :-
	partition(L,X,L1,L2),
	qsort(L2,R1,R0),
	qsort(L1,R,[X|R1]).
qsort([],R,R).

partition([X|L],Y,[X|L1],L2) :-
	X<Y, !,
	partition(L,Y,L1,L2).
partition([X|L],Y,L1,[X|L2]) :-
	partition(L,Y,L1,L2).
partition([],_,[],[]).

list50([27,74,17,33,94,18,46,83,65,2,
	32,53,28,85,99,47,28,82,6,11,
	55,29,39,81,90,37,10,0,66,51,
	7,21,85,27,31,63,75,4,95,99,
	11,28,61,74,18,92,40,53,59,8]).



%	serialize (palin25)
%	from Warren's thesis

palin25 :-
	palin25(P),
	serialize(P,X).
	%write(X),nl.

serialize(L,R) :-
	pairlists(L,R,A),
	arrange(A,T),
	numbered(T,1,N).

pairlists([X|L], [Y|R], [pair(X,Y)|A]) :- pairlists(L,R,A).
pairlists([], [], []).

arrange([X|L], tree(T1, X, T2)) :-
	split(L, X, L1, L2),
	arrange(L1, T1),
	arrange(L2, T2).
arrange([], void).

split([X|L], X, L1, L2) :- !, split(L, X, L1, L2).
split([X|L], Y, [X|L1], L2) :- before(X,Y), !, split(L,Y,L1,L2).
split([X|L], Y, L1, [X|L2]) :- before(Y,X), !, split(L,Y,L1,L2).
split([], _, [], []).

before(pair(X1,Y1), pair(X2,Y2)) :- X1 < X2.

numbered(tree(T1, pair(X,N1), T2), N0, N) :-
	numbered(T1, N0, N1),
	%is(N2,N1,+,1),
	N2 is N1+1,
	numbered(T2,N2,N).
numbered(_,N,N).

palin25("ABLE WAS I ERE I SAW ELBA").


% The sieve of Eratosthenes, from Clocksin & Mellish (pri2)
%	finding the prime numbers up to 98.	

%sieve :- primes(98, X), write(X), nl.
sieve :- primes(98, X).

primes(Limit, Ps) :- integers(2, Limit, Is), sift(Is, Ps).

integers(Low, High, [Low | Rest]) :- 
	Low =< High, !,
	M is Low+1,
	integers(M, High, Rest).
integers(_,_,[]).

sift([],[]).
sift([I | Is], [I | Ps]) :- remove(I,Is,New), sift(New, Ps).

remove(P,[],[]).
remove(P,[I | Is], [I | Nis]) :- \+(0 is I mod P), !, remove(P,Is,Nis).
remove(P,[I | Is], Nis) :- 0 is I mod P, !, remove(P,Is,Nis).

